package com.wiscamp.ninechapters.problems.infrastructure.repositories;

import com.wiscamp.ninechapters.common.core.CollectionHelper;
import com.wiscamp.ninechapters.problems.domain.models.sheets.Sheet;
import com.wiscamp.ninechapters.problems.domain.models.sheets.SheetDetail;
import com.wiscamp.ninechapters.problems.domain.models.sheets.SheetAnswer;
import com.wiscamp.ninechapters.problems.domain.repositories.SheetRepository;
import com.wiscamp.ninechapters.problems.enums.AnswerTypes;
import com.wiscamp.ninechapters.problems.infrastructure.converters.SheetConverter;
import com.wiscamp.ninechapters.problems.infrastructure.mappers.sheets.SheetDetailMapper;
import com.wiscamp.ninechapters.problems.infrastructure.mappers.sheets.SheetMapper;
import com.wiscamp.ninechapters.problems.infrastructure.mappers.sheets.SheetAnswerMapper;
import cube.common.core.ParseUtils;
import cube.ddd.aspect.HandleDataException;
import cube.ddd.aspect.HandleServiceException;
import cube.ddd.domain.BaseRepository;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;

@Repository
public class SheetRepositoryImpl extends BaseRepository implements SheetRepository {

    private final SheetMapper sheetMapper;

    private final SheetDetailMapper sheetDetailMapper;

    private final SheetAnswerMapper sheetAnswerMapper;

    private final SheetBuilder sheetBuilder;

    private final ProblemBuilder problemBuilder;

    public SheetRepositoryImpl(SheetMapper sheetMapper, SheetDetailMapper sheetDetailMapper, SheetAnswerMapper sheetAnswerMapper, SheetBuilder sheetBuilder, ProblemBuilder problemBuilder) {
        this.sheetMapper = sheetMapper;
        this.sheetDetailMapper = sheetDetailMapper;
        this.sheetAnswerMapper = sheetAnswerMapper;
        this.sheetBuilder = sheetBuilder;
        this.problemBuilder = problemBuilder;
    }

    // region sheet
    @HandleDataException
    public Sheet getSheet(long sheetId) {
        return sheetBuilder.getSheet(sheetId);
    }

    @HandleDataException
    public Sheet getSheetByTask(@Min(0) long taskId) {
        var sheetPO = sheetMapper.findByTask(taskId);
        if (Objects.isNull(sheetPO)) return null;
        sheetBuilder.loadSheetPODetails(sheetPO);
        return sheetBuilder.toSheet(sheetPO);
    }

    @HandleDataException
    public Collection<Sheet> getSheetsByUser(long userId) {
        var sheetPOs = sheetMapper.findListByUser(userId);
        return CollectionHelper.convertToArrayList(sheetPOs, SheetConverter.Instance::toSheet);
    }

    @HandleDataException
    public int getSheetsQuantityByDate(@NotBlank LocalDateTime startDate, @NotBlank LocalDateTime endDate) {
        return sheetMapper.findSheetQuantityByDate(startDate, endDate);
    }

    @HandleDataException
    public int getSheetsQuantityByUser(@Min(0) long userId) {
        return sheetMapper.findSheetQuantityByUser(userId);
    }

    @HandleDataException
    public Sheet saveSheet(Sheet sheet) {
        var sheetPO = sheetBuilder.toSheetPO(sheet);
        if (Objects.isNull(sheetPO)) return null;

        var savedPO = sheetMapper.saveAndFlush(sheetPO);
        var details = sheet.getDetails();
        if (!details.isEmpty()) {
            for (var sheetDetail : details) {
                sheetDetail.setSheetId(savedPO.getSheetId());
                saveSheetDetail(sheetDetail);
            }
        }
        return getSheet(savedPO.getSheetId());
    }

    @HandleDataException
    public SheetAnswer saveSheetAnswer(SheetAnswer sheetAnswer) {
        var po = sheetBuilder.toSheetAnswerPO(sheetAnswer);
        if (Objects.isNull(po)) return null;

        // 忽略的答案不进行处理，直接存储
        if (!po.isSkipped()) {
            // 处理Option Answer
            var answerType = AnswerTypes.valueOf(sheetAnswer.getContentTypeId());
            if (answerType == AnswerTypes.OPTION) {
                var optionId = ParseUtils.parseLong(po.getOptionContentText());
                var prefix = problemBuilder.getOptionPrefix(optionId);
                po.setContentText(prefix);
            }

            if (answerType == AnswerTypes.MULTIPLE_OPTION) {
                var optionIdTexts = po.getOptionContentText().split(",");
                var optionPrefixs = new ArrayList<String>();
                for (var optionIdText : optionIdTexts) {
                    var optionId = ParseUtils.parseLong(optionIdText);
                    var prefix = problemBuilder.getOptionPrefix(optionId);
                    optionPrefixs.add(prefix);
                }
                po.setContentText(StringUtils.join(optionPrefixs, ","));
            }
        }

        var savedPO = sheetAnswerMapper.saveAndFlush(po);
        return sheetBuilder.toSheetAnswer(savedPO);
    }

    @HandleDataException
    public SheetDetail saveSheetDetail(SheetDetail sheetDetail) {
        var po = sheetBuilder.toSheetDetailPO(sheetDetail);
        if (Objects.isNull(po)) return null;
        var savedPO = sheetDetailMapper.saveAndFlush(po);
        savedPO.getSheetAnswers().clear();

        var savedSheetAnswers = new ArrayList<SheetAnswer>();
        for (var sheetAnswer : sheetDetail.getSheetAnswers()) {
            sheetAnswer.setSheetDetailId(savedPO.getDetailId());
            var savedSheetAnswer = saveSheetAnswer(sheetAnswer);
            savedSheetAnswers.add(savedSheetAnswer);
        }

        var detail = sheetBuilder.toSheetDetail(savedPO);
        detail.getSheetAnswers().addAll(savedSheetAnswers);
        return detail;
    }


    // endregion

    // region sheet details
    public SheetDetail findSheetDetail(@NotBlank Collection<SheetDetail> details, @Min(0) long questionId) {
        var optionalDetail = details.stream().filter(e->e.getQuestionId() == questionId).findFirst();
        return optionalDetail.orElse(null);
    }

    @HandleServiceException
    public long getSheetDetailId(@NotBlank Collection<SheetDetail> details, @Min(0) long problemId, @Min(0) long questionId) {
        for (var detail : details) {
            if (detail.getProblemId() == problemId && detail.getQuestionId() == questionId)
                return detail.getDetailId();
        }
        return 0;
    }
    // endregion

}
